// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.iso;

import zombie.debug.LineDrawer;
import zombie.iso.SpriteDetails.IsoFlagType;

public class NearestWalls {
    private static final int CPW = 10;
    private static final int CPWx4 = 40;
    private static final int LEVELS = 8;
    private static int CHANGE_COUNT = 0;
    private static int renderX;
    private static int renderY;
    private static int renderZ;

    public static void chunkLoaded(IsoChunk chunk) {
        CHANGE_COUNT++;
        if (CHANGE_COUNT < 0) {
            CHANGE_COUNT = 0;
        }

        chunk.nearestWalls.changeCount = -1;
    }

    private static void calcDistanceOnThisChunkOnly(IsoChunk isoChunk) {
        byte[] byte0 = isoChunk.nearestWalls.distanceSelf;

        for (int int0 = 0; int0 < 8; int0++) {
            for (int int1 = 0; int1 < 10; int1++) {
                byte byte1 = -1;

                for (int int2 = 0; int2 < 10; int2++) {
                    isoChunk.nearestWalls.closest[int2 + int1 * 10 + int0 * 10 * 10] = -1;
                    int int3 = int2 * 4 + int1 * 40 + int0 * 10 * 40;
                    byte0[int3 + 0] = byte1 == -1 ? -1 : (byte)(int2 - byte1);
                    byte0[int3 + 1] = -1;
                    IsoGridSquare isoGridSquare0 = isoChunk.getGridSquare(int2, int1, int0);
                    if (isoGridSquare0 != null
                        && (
                            isoGridSquare0.Is(IsoFlagType.WallW)
                                || isoGridSquare0.Is(IsoFlagType.DoorWallW)
                                || isoGridSquare0.Is(IsoFlagType.WallNW)
                                || isoGridSquare0.Is(IsoFlagType.WindowW)
                        )) {
                        byte1 = (byte)int2;
                        byte0[int3 + 0] = 0;

                        for (int int4 = int2 - 1; int4 >= 0; int4--) {
                            int3 = int4 * 4 + int1 * 40 + int0 * 10 * 40;
                            if (byte0[int3 + 1] != -1) {
                                break;
                            }

                            byte0[int3 + 1] = (byte)(byte1 - int4);
                        }
                    }
                }
            }

            for (int int5 = 0; int5 < 10; int5++) {
                byte byte2 = -1;

                for (int int6 = 0; int6 < 10; int6++) {
                    int int7 = int5 * 4 + int6 * 40 + int0 * 10 * 40;
                    byte0[int7 + 2] = byte2 == -1 ? -1 : (byte)(int6 - byte2);
                    byte0[int7 + 3] = -1;
                    IsoGridSquare isoGridSquare1 = isoChunk.getGridSquare(int5, int6, int0);
                    if (isoGridSquare1 != null
                        && (
                            isoGridSquare1.Is(IsoFlagType.WallN)
                                || isoGridSquare1.Is(IsoFlagType.DoorWallN)
                                || isoGridSquare1.Is(IsoFlagType.WallNW)
                                || isoGridSquare1.Is(IsoFlagType.WindowN)
                        )) {
                        byte2 = (byte)int6;
                        byte0[int7 + 2] = 0;

                        for (int int8 = int6 - 1; int8 >= 0; int8--) {
                            int7 = int5 * 4 + int8 * 40 + int0 * 10 * 40;
                            if (byte0[int7 + 3] != -1) {
                                break;
                            }

                            byte0[int7 + 3] = (byte)(byte2 - int8);
                        }
                    }
                }
            }
        }
    }

    private static int getIndex(IsoChunk isoChunk, int int2, int int1, int int0) {
        return (int2 - isoChunk.wx * 10) * 4 + (int1 - isoChunk.wy * 10) * 40 + int0 * 10 * 40;
    }

    private static int getNearestWallOnSameChunk(IsoChunk isoChunk, int int1, int int2, int int3, int int4) {
        NearestWalls.ChunkData chunkData = isoChunk.nearestWalls;
        if (chunkData.changeCount != CHANGE_COUNT) {
            calcDistanceOnThisChunkOnly(isoChunk);
            chunkData.changeCount = CHANGE_COUNT;
        }

        int int0 = getIndex(isoChunk, int1, int2, int3);
        return chunkData.distanceSelf[int0 + int4];
    }

    private static boolean hasWall(IsoChunk isoChunk, int int0, int int1, int int2, int int3) {
        return getNearestWallOnSameChunk(isoChunk, int0, int1, int2, int3) == 0;
    }

    private static int getNearestWallWest(IsoChunk isoChunk0, int int1, int int2, int int3) {
        byte byte0 = 0;
        byte byte1 = -1;
        byte byte2 = 0;
        int int0 = getNearestWallOnSameChunk(isoChunk0, int1, int2, int3, byte0);
        if (int0 != -1) {
            return int1 - int0;
        } else {
            for (int int4 = 1; int4 <= 3; int4++) {
                IsoChunk isoChunk1 = IsoWorld.instance.CurrentCell.getChunk(isoChunk0.wx + int4 * byte1, isoChunk0.wy + int4 * byte2);
                if (isoChunk1 == null) {
                    break;
                }

                int int5 = (isoChunk1.wx + 1) * 10 - 1;
                int0 = getNearestWallOnSameChunk(isoChunk1, int5, int2, int3, byte0);
                if (int0 != -1) {
                    return int5 - int0;
                }
            }

            return -1;
        }
    }

    private static int getNearestWallEast(IsoChunk isoChunk0, int int1, int int2, int int3) {
        byte byte0 = 1;
        byte byte1 = 1;
        byte byte2 = 0;
        int int0 = getNearestWallOnSameChunk(isoChunk0, int1, int2, int3, byte0);
        if (int0 != -1) {
            return int1 + int0;
        } else {
            for (int int4 = 1; int4 <= 3; int4++) {
                IsoChunk isoChunk1 = IsoWorld.instance.CurrentCell.getChunk(isoChunk0.wx + int4 * byte1, isoChunk0.wy + int4 * byte2);
                if (isoChunk1 == null) {
                    break;
                }

                int int5 = isoChunk1.wx * 10;
                int0 = hasWall(isoChunk1, int5, int2, int3, 0) ? 0 : getNearestWallOnSameChunk(isoChunk1, int5, int2, int3, byte0);
                if (int0 != -1) {
                    return int5 + int0;
                }
            }

            return -1;
        }
    }

    private static int getNearestWallNorth(IsoChunk isoChunk0, int int1, int int2, int int3) {
        byte byte0 = 2;
        byte byte1 = 0;
        byte byte2 = -1;
        int int0 = getNearestWallOnSameChunk(isoChunk0, int1, int2, int3, byte0);
        if (int0 != -1) {
            return int2 - int0;
        } else {
            for (int int4 = 1; int4 <= 3; int4++) {
                IsoChunk isoChunk1 = IsoWorld.instance.CurrentCell.getChunk(isoChunk0.wx + int4 * byte1, isoChunk0.wy + int4 * byte2);
                if (isoChunk1 == null) {
                    break;
                }

                int int5 = (isoChunk1.wy + 1) * 10 - 1;
                int0 = getNearestWallOnSameChunk(isoChunk1, int1, int5, int3, byte0);
                if (int0 != -1) {
                    return int5 - int0;
                }
            }

            return -1;
        }
    }

    private static int getNearestWallSouth(IsoChunk isoChunk0, int int1, int int2, int int3) {
        byte byte0 = 3;
        byte byte1 = 0;
        byte byte2 = 1;
        int int0 = getNearestWallOnSameChunk(isoChunk0, int1, int2, int3, byte0);
        if (int0 != -1) {
            return int2 + int0;
        } else {
            for (int int4 = 1; int4 <= 3; int4++) {
                IsoChunk isoChunk1 = IsoWorld.instance.CurrentCell.getChunk(isoChunk0.wx + int4 * byte1, isoChunk0.wy + int4 * byte2);
                if (isoChunk1 == null) {
                    break;
                }

                int int5 = isoChunk1.wy * 10;
                int0 = hasWall(isoChunk1, int1, int5, int3, 2) ? 0 : getNearestWallOnSameChunk(isoChunk1, int1, int5, int3, byte0);
                if (int0 != -1) {
                    return int5 + int0;
                }
            }

            return -1;
        }
    }

    public static void render(int x, int y, int z) {
        IsoChunk isoChunk = IsoWorld.instance.CurrentCell.getChunkForGridSquare(x, y, z);
        if (isoChunk != null) {
            if (renderX != x || renderY != y || renderZ != z) {
                renderX = x;
                renderY = y;
                renderZ = z;
                System.out.println("ClosestWallDistance=" + ClosestWallDistance(isoChunk, x, y, z));
            }

            int int0 = getNearestWallWest(isoChunk, x, y, z);
            if (int0 != -1) {
                DrawIsoLine((float)int0, (float)y + 0.5F, (float)x + 0.5F, (float)y + 0.5F, (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
                DrawIsoLine((float)int0, (float)y, (float)int0, (float)(y + 1), (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
            }

            int0 = getNearestWallEast(isoChunk, x, y, z);
            if (int0 != -1) {
                DrawIsoLine((float)int0, (float)y + 0.5F, (float)x + 0.5F, (float)y + 0.5F, (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
                DrawIsoLine((float)int0, (float)y, (float)int0, (float)(y + 1), (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
            }

            int int1 = getNearestWallNorth(isoChunk, x, y, z);
            if (int1 != -1) {
                DrawIsoLine((float)x + 0.5F, (float)int1, (float)x + 0.5F, (float)y + 0.5F, (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
                DrawIsoLine((float)x, (float)int1, (float)(x + 1), (float)int1, (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
            }

            int1 = getNearestWallSouth(isoChunk, x, y, z);
            if (int1 != -1) {
                DrawIsoLine((float)x + 0.5F, (float)int1, (float)x + 0.5F, (float)y + 0.5F, (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
                DrawIsoLine((float)x, (float)int1, (float)(x + 1), (float)int1, (float)z, 1.0F, 1.0F, 1.0F, 1.0F, 1);
            }
        }
    }

    private static void DrawIsoLine(
        float float1, float float2, float float6, float float7, float float3, float float9, float float10, float float11, float float12, int _int
    ) {
        float float0 = IsoUtils.XToScreenExact(float1, float2, float3, 0);
        float float4 = IsoUtils.YToScreenExact(float1, float2, float3, 0);
        float float5 = IsoUtils.XToScreenExact(float6, float7, float3, 0);
        float float8 = IsoUtils.YToScreenExact(float6, float7, float3, 0);
        LineDrawer.drawLine(float0, float4, float5, float8, float9, float10, float11, float12, _int);
    }

    public static int ClosestWallDistance(IsoGridSquare square) {
        return square != null && square.chunk != null ? ClosestWallDistance(square.chunk, square.x, square.y, square.z) : 127;
    }

    public static int ClosestWallDistance(IsoChunk chunk, int x, int y, int z) {
        if (chunk == null) {
            return 127;
        } else {
            NearestWalls.ChunkData chunkData = chunk.nearestWalls;
            byte[] byte0 = chunkData.closest;
            if (chunkData.changeCount != CHANGE_COUNT) {
                calcDistanceOnThisChunkOnly(chunk);
                chunkData.changeCount = CHANGE_COUNT;
            }

            int int0 = x - chunk.wx * 10 + (y - chunk.wy * 10) * 10 + z * 10 * 10;
            byte byte1 = byte0[int0];
            if (byte1 != -1) {
                return byte1;
            } else {
                int int1 = getNearestWallWest(chunk, x, y, z);
                int int2 = getNearestWallEast(chunk, x, y, z);
                int int3 = getNearestWallNorth(chunk, x, y, z);
                int int4 = getNearestWallSouth(chunk, x, y, z);
                if (int1 == -1 && int2 == -1 && int3 == -1 && int4 == -1) {
                    return byte0[int0] = (byte)127;
                } else {
                    int int5 = -1;
                    if (int1 != -1 && int2 != -1) {
                        int5 = int2 - int1;
                    }

                    int int6 = -1;
                    if (int3 != -1 && int4 != -1) {
                        int6 = int4 - int3;
                    }

                    if (int5 != -1 && int6 != -1) {
                        return byte0[int0] = (byte)Math.min(int5, int6);
                    } else if (int5 != -1) {
                        return byte0[int0] = (byte)int5;
                    } else if (int6 != -1) {
                        return byte0[int0] = (byte)int6;
                    } else {
                        IsoGridSquare isoGridSquare = chunk.getGridSquare(x - chunk.wx * 10, y - chunk.wy * 10, z);
                        if (isoGridSquare != null && isoGridSquare.isOutside()) {
                            int1 = int1 == -1 ? 127 : x - int1;
                            int2 = int2 == -1 ? 127 : int2 - x - 1;
                            int3 = int3 == -1 ? 127 : y - int3;
                            int4 = int4 == -1 ? 127 : int4 - y - 1;
                            return byte0[int0] = (byte)Math.min(int1, Math.min(int2, Math.min(int3, int4)));
                        } else {
                            return byte0[int0] = (byte)127;
                        }
                    }
                }
            }
        }
    }

    public static final class ChunkData {
        int changeCount = -1;
        final byte[] distanceSelf = new byte[3200];
        final byte[] closest = new byte[800];
    }
}
